﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Controllers;
using SageKing.OpenIddict.UI.Infrastructure;
using SageKing.OpenIddict.UI.Infrastructure.Data;
using SageKing.OpenIddict.UI.Infrastructure.Features;
using SageKing.OpenIddict.UI.Infrastructure.Services;

namespace SageKing.Extensions;

[ExcludeFromCodeCoverage]
public static class ModuleExtensions
{
    public static IModule UseOpenIddictUIInfrastructureServer(this IModule module, Action<OpenIddictUIInfrastructureFeature>? configure = default)
    {

        module.Configure<OpenIddictUIInfrastructureFeature>(feature =>
        {
            configure?.Invoke(feature);
        });

        module.UseIceMediatR(o => o.MediatRServiceConfiguration += a =>
        {
            a.RegisterServicesFromAssembly(typeof(OpenIddictUIInfrastructureFeature).Assembly);
        });

        return module;
    }
    public static OpenIddictBuilder AddUIStore(this OpenIddictBuilder builder, Action<OpenIddictUIStoreOptions> storeOptionsAction = null
)
    {
        builder.Services.AddInfrastructureServices();

        var coreBuilder = new OpenIddictCoreBuilder(builder.Services)
          .UseEFCoreUIStore<OpenIddictUIContext>();

        builder.Services
          .AddOpenIddictUIStore<OpenIddictUIContext>(storeOptionsAction);

        return builder;
    }
    public static IServiceCollection AddInfrastructureServices(this IServiceCollection services
  )
    {
        services.AddScoped(typeof(IAsyncRepository<,>), typeof(EfRepository<,>));

        services.AddTransient<IScopeRepository, ScopeRepository<OpenIddictUIContext>>();
        services.AddTransient<IApplicationRepository, ApplicationRepository<OpenIddictUIContext>>();

        services.AddTransient<IScopeService, ScopeService>();
        services.AddTransient<IApplicationService, ApplicationService>();

        //注入
        // Override default sender
        services.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailKitEmailSender>();

        services.AddSingleton<IEmailSender<AppUser>, SKIdentityNoOpEmailSender>();

        return services;
    }

    public static OpenIddictEntityFrameworkCoreBuilder UseEFCoreUIStore<TContext>(this OpenIddictCoreBuilder builder
    ) where TContext : IOpenIddictUIContext
    {
        builder
          .UseEntityFrameworkCore()
          .UseDbContext<OpenIddictUIContext>();

        return new OpenIddictEntityFrameworkCoreBuilder(builder.Services);
    }

    public static IServiceCollection AddOpenIddictUIStore<TContext>(this IServiceCollection services,
      Action<OpenIddictUIStoreOptions> storeOptionsAction = null)
      where TContext : DbContext, IOpenIddictUIContext
    {
        var options = new OpenIddictUIStoreOptions();
        services.AddSingleton(options);
        storeOptionsAction?.Invoke(options);

        if (options.ResolveDbContextOptions != null)
        {
            services.AddDbContext<TContext>(options.ResolveDbContextOptions);
        }
        else
        {
            services.AddDbContext<TContext>(dbCtxBuilder =>
            {
                options.OpenIddictUIContext?.Invoke(dbCtxBuilder);
            });
        }

        services.AddScoped<IOpenIddictUIContext, TContext>();

        return services;
    }
}
